﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Extensions.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Serilog;
using Common;
using Common.DataModels;
using Extensions.ConfigurationCenter.Consul;
using Microsoft.Extensions.Hosting;
using Extensions.Services.Authorization;
using Extensions.Filters;
using Microsoft.EntityFrameworkCore;

namespace Extensions
{
    public static class AddAllExtensions
    {
        /// <summary>
        /// 注册所有service的入口
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IServiceCollection AddAllServiceSetup(this IServiceCollection services,Action<SetupTypesConfig> setupOptions)
        {
            if (services==null)
            {
                throw new ArgumentNullException(nameof(services));
            }
            // 获取配置
            var config = new SetupTypesConfig();
            setupOptions(config);
            // 注入baseRepository 和baseService
            //services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
            // 注入公共的服务
            services.AddSwaggerSetup()
                .AddMiniProfilerSetup()
                .AddCorsSetup()
                .AddAuthorizationSetup()
                .AddAutoMapperSetup(config.AutoMapperConfigRegisterAssemblies)
                .AddFlunetValidationSetup(config)
                .AddMemoryCacheSetup()
                .AddHttpClientSetup()
                .AddMediatRSetup(config)
                .AddRabbitMQSetup(config)
                .AddConsulSetup()
                .AddRedisSetup()
                .AddHealthCheckSetup()
                .AddEsSetup();
            return services;
        }
        /// <summary>
        /// 添加所有中间件
        /// </summary>
        /// <param name="app"></param>
        /// <param name="builder"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IApplicationBuilder AddAllMiddlewareSetup(this IApplicationBuilder app, WebApplication builder)
        {
            ArgumentNullException.ThrowIfNull(app);
            ArgumentNullException.ThrowIfNull(builder);
            var env = builder.Environment;
            //var lifeTime = builder.Lifetime;
            app.UseSwaggerSetup(env)
                .UseMiniProfilerSetup(env)
                .UseCorsSetup(env)
                .UseRabbitMQSetup()
                .UseDefaultFiles()
                .UseStaticFiles()
                .UseHealthChecks(Appsettings.app("HealthCheckPath"));
            return app;
        }
        // 可以用泛型 添加一个dbcontext 的  如果参数 太多  可以创建一个类 用来传参


        /// <summary>
        /// 提供了可以初始化db的泛型
        /// </summary>
        /// <typeparam name="TDbContext"></typeparam>
        /// <param name="builder"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static WebApplicationBuilder AddAllSetup<TDbContext>(this WebApplicationBuilder builder,
            Action<SetupTypesConfig> config) where TDbContext : DbContext
        {
            builder.AddAllSetup(config);
            builder.Services.AddEFCoreSetup<TDbContext>();
            return builder;
        }
        /// <summary>
        /// 初始化默认的控制器
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddDefaultController(this IServiceCollection services)
        {
            ArgumentNullException.ThrowIfNull(services);
            services.AddControllers(configure =>
            {
                // 可以添加过滤器
                configure.Filters.Add(typeof(GlobalExceptionFilter));
                // 过滤器的顺序 从小到大  全局的为10、Controller上的为20、Action上的为30.也就是说，Filter的执行顺序为
                // 如果是标签  或者同级的 那么写在上面的先执行
                configure.Filters.Add(typeof(FlunetValidationFilter));
                configure.Filters.Add(typeof(TransactionFilter));
                // 暂时不写 因为  过滤器 一般要指定顺序 比较小的数先执行  比如 全局过滤器是1  那么他就是第一个执行的
                //if (config.FilterTypes!=null&&config.FilterTypes.Length>0)
                //{
                //    foreach (var configFilterType in config.FilterTypes)
                //    {
                //        configure.Filters.Add()
                //    }
                //}
            }).AddNewtonsoftJson(options =>
            {
                //忽略循环引用
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                //不使用驼峰样式的key
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                //设置时间格式
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                //忽略Model中为null的属性
                //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                //设置本地时间而非UTC时间
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
                //添加Enum转string
                options.SerializerSettings.Converters.Add(new StringEnumConverter());
                // long转string 直接使用long类型  序列化的时候会出问题
                options.SerializerSettings.Converters.Add(new JsonNumberConverter());
            })
                .ConfigureApiBehaviorOptions(options =>
            {
                // 关闭默认的模型验证
                options.SuppressModelStateInvalidFilter = true;

            })
                .AddJsonOptions(config =>
            {
                // 不设置属性名字序列化的策略   首字母没有大小写校验
                config.JsonSerializerOptions.PropertyNamingPolicy = null;
            });
            //支持编码大全 例如:支持 System.Text.Encoding.GetEncoding("GB2312")  System.Text.Encoding.GetEncoding("GB18030") 
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            return services;
        }
        /// <summary>
        /// 从日志 读取seiloag的配置
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static WebApplicationBuilder AddSerilogSetup(this WebApplicationBuilder builder) 
        {
            ArgumentNullException.ThrowIfNull(builder);
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(builder.Configuration)
                .Enrich.FromLogContext() // 注册日志上下文  为了日志输出的时候 可以使用上下文中的属性
                .CreateLogger();
            Log.Information("Starting web host");
            builder.Host.UseSerilog(Log.Logger, dispose: true);
            return builder;
        }

        /// <summary>
        /// 注册公共的服务 db需要自己注册
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="config">配置类</param>
        /// <returns></returns>
        public static WebApplicationBuilder AddAllSetup(this WebApplicationBuilder builder,Action<SetupTypesConfig> setupOptions)
        {
            // 获取配置
            var config = new SetupTypesConfig();
            setupOptions.Invoke(config);
            var services = builder.Services;
            // Add services to the container.
            builder.AddSerilogSetup();
            // 添加默认的控制器
            services.AddDefaultController();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            services.AddEndpointsApiExplorer();
            //初始化配置读取类
            services.AddSingleton(new Appsettings(builder.Configuration));
            // 加载配置中心中的配置
            builder.Configuration.AddConsulConfigurationCenterSetup();
            // 注册一些公共的服务
            services.AddAllServiceSetup(setupOptions);
                //.AddEFCoreSetup<T>();
            // 注册autofac  替换.net core自带的依赖注入
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureContainer<ContainerBuilder>(container =>
                {
                    container.RegisterModule(
                        new AddAutoFac(config.AutofacRegisterTypes.ToList(),
                            config.AutofacInterceptTypes==null?new List<Type>():config.AutofacInterceptTypes.ToList()));
                });
           
            return builder;
        }
    }


   

}
